/**
 * 
 */
package slash.client.controllers;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import slash.client.swing.controls.GamePanel;
import slash.game.Board;
import slash.game.Cell;
import slash.game.Game;
import slash.game.Movement;
import slash.game.Unit;

/**
 * Central controller for events and actions in the game.
 * 
 * @author gsh
 */
public final class GameController {
	private static Logger logger = Logger.getLogger(GameController.class
			.getName());
	private static GameController controller = new GameController();

	private List<GameListener> gameListeners = new ArrayList<GameListener>();
	private List<ChatListener> chatListeners = new ArrayList<ChatListener>();
	private Game game;
	private GamePanel gamePanel;

	private GameController() {
		// Prevent construction by other classes.
		setGame(Game.Create());
	}

	/**
	 * Returns singleton instance of the GameController
	 * 
	 * @return
	 */
	public static GameController get() {
		return controller;
	}

	public boolean canExit() {
		return true;
	}

	public void saveGame() {
		logger.info("saveGame request");
	}

	public void addGameListener(GameListener listener) {
		gameListeners.add(listener);
	}

	public void removeGameListener(GameListener listener) {
		gameListeners.remove(listener);
	}

	public void addChatListener(ChatListener listener) {
		chatListeners.add(listener);
	}

	public void removeChatListener(ChatListener listener) {
		chatListeners.remove(listener);
	}
	
	public void fireStart() {
		logger.info("Starting game");
		for (GameListener listener : gameListeners) {
			listener.start();
		}
	}

	public void fireEnd() {
		logger.info("Ending game");
		for (GameListener listener : gameListeners) {
			listener.end();
		}
	}
	
	// Should generalize chat to events probably
	public void fireChat(String msg) {
		logger.info("Chat: "+msg);
		for (ChatListener listener : chatListeners) {
			listener.chat(msg);
		}	
	}

	public boolean CanMove(Unit unit, Cell destination) {
		// TODO: use unit somehow
		switch (destination.getTerrain()) {
		case None:
			return destination.getContents().isEmpty();
		default:
			return false;
		}
	}

	public boolean Move(Unit unit, Movement direction) {
		Cell location = unit.getCell();
		Board board = location.getBoard();

		int x = location.getX();
		int y = location.getY();
		switch (direction) {
		case Down:
			y = y+1;
			break;
		case Up:
			y = y-1;
			break;
		case Left:
			x = x-1;
			break;
		case Right:
			x = x+1;
			break;
		}
		
		logger.info("Moving: "+x+","+y);
		// Make sure we don't walk off the board
		if (x < 0 || x >= board.getWidth() || y < 0 || y >= board.getHeight()) {
			logger.info("move failed");
			return false;
		}
		Cell target = board.getCell(x, y);
		if (CanMove(unit, target)) {
			logger.info("trying to move");
			GameController.get().fireChat("moved!");
			// TODO: consolidate this "move" logic somewhere
			target.getContents().add(unit);
			location.getContents().remove(unit);
			unit.setCell(target);
			return true;
		}
		
		logger.info("move failed");
		return false;
	}

	/**
	 * @param gamePanel the gamePanel to set
	 */
	public void setGamePanel(GamePanel gamePanel) {
		this.gamePanel = gamePanel;
	}

	/**
	 * @return the gamePanel
	 */
	public GamePanel getGamePanel() {
		return gamePanel;
	}

	/**
	 * @param game the game to set
	 */
	private void setGame(Game game) {
		this.game = game;
	}

	/**
	 * @return the game
	 */
	public Game getGame() {
		return game;
	}

}
